/**
 * @brief 3.2.3 处理string对象中的字符
 * 在cctype头文件中定义了一组标准库函数处理这部分工作
 * @param argc 
 * @param argv 
 * @return int 
 */
#include <iostream>
#include <string>
#include <cctype> // 定义了一组标准库函数处理string对象中的字符
using std::cin, std::cout, std::endl;
using std::string, std::getline;
int main(int argc, char const *argv[])
{
    // C++标准库中除了定义C++语言特有的功能外，也兼容了C语言的标准库。
    // C语言的头文件形如name.h，C++则将这些文件命名为cname。
    // 也就是去掉了.h后缀，而在文件名name之前添加了字母c，这里的c表示这是一个属于C语言标准库的头文件。

    // 范围for循环
    string str("some string");
    for(auto c : str) // 这里c的类型是char
    {
        cout << c << endl;
    }

    string s("Hello World!!!");
    decltype(s.size()) punct_cnt = 0; // 定义变量punct_cnt与s.size()的返回类型一致
    for(auto c : s)
    {
        if(ispunct(c)) // 如果是标点符号
            ++punct_cnt;
    }
    cout << punct_cnt << " punchtuation characters in " << s << endl;

    // 使用范围for语句改变字符串中的字符
    // 如果想要改变string对象中字符的值，必须把循环变量定义成引用类型
    for (auto &c : s)
    {
        c = toupper(c); // c是个引用，因此赋值语句将改变s中字符的值
    }
    cout << s << endl;

    // 使用下标运算符（[]）只处理一部分字符
    // 把string对象中的第一个字母大写化
    string s1 = "some string";
    if(!s1.empty())
        s[0] = toupper(s[0]);
    // 把string对象中的第一个单词大写化
    // 依次处理s1中的字符，直至我们处理完全部字符或遇到一个空白
    for(decltype(s1.size()) index = 0; index != s1.size() && !isspace(s[index]); ++index)
    {
        s[index] = toupper(s[index]);
    }
    
    // 编写一个程序把0到15之间的十进制数转换成对应的十六进制形式
    const string hexdigits = "0123456789ABCDEF";
    cout << "Enter a series of numbers between 0 and 15"
        << " separated by spaces. Hit ENTER when finished: " << endl;
    string result;
    string::size_type n; // 用于保存从输入流读取的数
    while (cin >> n)
    {
        if(n < hexdigits.size())
            result += hexdigits[n];
    }
    cout << "Your hex number is: " + result << endl;

    return 0;
}
